#ifndef __LL_COMMAND_LIST_HPP__
#define __LL_COMMAND_LIST_HPP__

#include "llCommandBase.hpp"
#include "llToken.hpp"

#include <boost/assign/list_of.hpp>
#include <boost/assert.hpp>
using namespace boost::assign;

#include <boost/tr1/memory.hpp>
using namespace std::tr1;


#include <vector>
#include <map>
using namespace std;


namespace llmake
{
	class llMakeDirectory;
	typedef shared_ptr<llMakeDirectory> llMakeDirectoryPtr;
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// include command 
	class llCommand__project : public llCommandBase
	{
// method
	public:
		llCommand__project(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llCommandBase(name,tokenList,owner)
		{}
		~llCommand__project(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llCommand__project>(new llCommand__project("project",tokenList,owner));
		}
		virtual void parseCommand(llCommandList &commands);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// self define command 
	class llPreProcess__selfDefine : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__selfDefine(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__selfDefine(){}
		static void createCommandInstance(
			const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__selfDefine>(new llPreProcess__selfDefine(name,tokenList,owner));
		}
		virtual void preProcess(llCommandList &commandsSrc);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// include command 
	class llPreProcess__include : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__include(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__include(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__include>(new llPreProcess__include("include",tokenList,owner));
		}
		virtual void preProcess(llCommandList &commandsSrc);
		bool checkFileExists(string &name);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// add_subdirectory command 
	class llPreProcess__add_subdirectory : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__add_subdirectory(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__add_subdirectory(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__add_subdirectory>(new llPreProcess__add_subdirectory("add_subdirectory",tokenList,owner));
		}
		virtual void preProcess(llCommandList &commandsSrc);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/

/// set command 
	class llPreProcess__set : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__set(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__set(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__set>(new llPreProcess__set("set",tokenList,owner));
		}
		virtual void preProcess(llCommandList &commandsSrc);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// macro command 
	class llPreProcess__macro : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__macro(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__macro(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__macro>(new llPreProcess__macro("macro",tokenList,owner));
		}
		virtual void preProcess(llCommandList &commandsSrc);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// endmacro command 
	class llPreProcess__endmacro : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__endmacro(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__endmacro(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__endmacro>(new llPreProcess__endmacro("endmacro",tokenList,owner));
		}
// members
	private:
	};	
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// if command 
	class llPreProcess__if : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__if(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__if(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__if>(new llPreProcess__if("if",tokenList,owner));
		}
		virtual void preProcess(llCommandList &commandsSrc);
	private:
		string calcExpr( list<llTokenList> &exprList );
		bool calcExpr( llTokenList &expr,string & result );
		void calcBlock(llCommandList &commandsSrc,map<string,llCommandList> &block,list<llTokenList> &exprList);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// endif command 
	class llPreProcess__endif : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__endif(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__endif(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__endif>(new llPreProcess__endif("endif",tokenList,owner));
		}
// members
	private:
	};	
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// else command 
	class llPreProcess__else : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__else(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__else(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__else>(new llPreProcess__else("else",tokenList,owner));
		}
// members
	private:
	};	
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// elseif command 
	class llPreProcess__elseif : public llPreProcessCommand
	{
// method
	public:
		llPreProcess__elseif(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llPreProcessCommand(name,tokenList,owner)
		{}
		~llPreProcess__elseif(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llPreProcess__elseif>(new llPreProcess__elseif("elseif",tokenList,owner));
		}
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// include_directories command 
	class llCompileCommand__include_directories : public llCompileCommand
	{
// method
	public:
		llCompileCommand__include_directories(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llCompileCommand(name,tokenList,owner)
		{}
		~llCompileCommand__include_directories(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llCompileCommand__include_directories>(new llCompileCommand__include_directories("include_directories",tokenList,owner));
		}
		virtual void parseCompileCommand(void);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// add_definitions command 
	class llCompileCommand__add_definitions : public llCompileCommand
	{
// method
	public:
		llCompileCommand__add_definitions(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llCompileCommand(name,tokenList,owner)
		{}
		~llCompileCommand__add_definitions(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llCompileCommand__add_definitions>(new llCompileCommand__add_definitions("include_directories",tokenList,owner));
		}
		virtual void parseCompileCommand(void);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/

/// add_library command 
	class llCompileCommand__add_library : public llCompileCommand
	{
// method
	public:
		llCompileCommand__add_library(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llCompileCommand(name,tokenList,owner)
		{}
		~llCompileCommand__add_library(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llCompileCommand__add_library>(new llCompileCommand__add_library("include_directories",tokenList,owner));
		}
		virtual void parseCompileCommand(void);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/

/// add_executable command 
	class llCompileCommand__add_executable : public llCompileCommand
	{
// method
	public:
		llCompileCommand__add_executable(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llCompileCommand(name,tokenList,owner)
		{}
		~llCompileCommand__add_executable(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llCompileCommand__add_executable> (new llCompileCommand__add_executable("add_executable",tokenList,owner));
		}
		virtual void parseCompileCommand(void);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/

/// target_link_libraries command 
	class llCompileCommand__target_link_libraries : public llCompileCommand
	{
// method
	public:
		llCompileCommand__target_link_libraries(const string &name,const llTokenList &tokenList,llMakeDirectoryPtr owner)
		 :llCompileCommand(name,tokenList,owner)
		{}
		~llCompileCommand__target_link_libraries(){}
		static void createCommandInstance(
			const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &p)
		{
			p = shared_ptr<llCompileCommand__target_link_libraries> (new llCompileCommand__target_link_libraries("target_link_libraries",tokenList,owner));
		}
		virtual void parseCompileCommand(void);
// members
	private:
	};
/****************************************************************************************************/
/****************************************************************************************************/
/****************************************************************************************************/
/// command instance map 
	typedef void (*commandInstanceCreator)(const llTokenList &tokenList,llMakeDirectoryPtr owner,shared_ptr<llCommandBase> &);
	typedef map<string,commandInstanceCreator> CommandInstanceCreatorMap;
	static CommandInstanceCreatorMap gCommandInstanceCreator = map_list_of \
		/* project commands */ \
		("project",llCommand__project::createCommandInstance)\
		/* preprocess commands */ \
		("include",llPreProcess__include::createCommandInstance)\
		("add_subdirectory",llPreProcess__add_subdirectory::createCommandInstance)\
		("set",llPreProcess__set::createCommandInstance)\
		("macro",llPreProcess__macro::createCommandInstance)\
		("endmacro",llPreProcess__endmacro::createCommandInstance)\
		("if",llPreProcess__if::createCommandInstance)\
		("endif",llPreProcess__endif::createCommandInstance)\
		("else",llPreProcess__else::createCommandInstance)\
		("elseif",llPreProcess__elseif::createCommandInstance)\
		 /* compiler commands */ \
		("include_directories",llCompileCommand__include_directories::createCommandInstance)\
		("add_definitions",llCompileCommand__add_definitions::createCommandInstance)\
		("add_library",llCompileCommand__add_library::createCommandInstance)\
		("add_executable",llCompileCommand__add_executable::createCommandInstance)\
		("target_link_libraries",llCompileCommand__target_link_libraries::createCommandInstance)\
		;
};

#endif // __LL_COMMAND_LIST_HPP__
